﻿using DotNetCommon;
using DotNetCommon.Extensions;
using System.Diagnostics;

namespace DeepClonePerformanceTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var list = new List<Person>();
            for (int i = 0; i < 100; i++)
            {
                list.Add(new Person()
                {
                    Id = i + 1,
                    Name = i + 1 + "-name",
                    Age = Random.Shared.Next(5, 10) + 15,
                    Birth = DateTime.Parse("1995-01-02"),
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                    Desc = i + 1 + "-desc",
                    Phone = "027-12345678",
                    Score = 95,
                    State = EnumState.Normal,
                    IdNull = i + 1,
                    IdNull2 = null,
                    CreateTimeNull = DateTime.Now,
                    CreateTimeNull2 = null,
                    StateNull = EnumState.Normal,
                    StateNull2 = null,
                });
            }
            //NewtonSoft 序列化反序列化
            Console.WriteLine();
            Console.WriteLine($"NewtonSoft--------------------------------List<Person>[Count=100]------------------------------------");
            TestNewtonSoft(list);

            //System.Text.Json
            Console.WriteLine();
            Console.WriteLine($"System.Text.Json 原生--------------------------------List<Person>[Count=100]------------------------------------");
            TestSystemTextJson(list);

            //ToJson
            Console.WriteLine();
            Console.WriteLine($"System.Text.Json 公用options----------------------------List<Person>[Count=100]------------------------------------");
            TestToJson(list);

            //ToJson
            Console.WriteLine();
            Console.WriteLine($"ToJson 公用options--------------------------------List<Person>[Count=100]------------------------------------");
            TestToJsonOptions(list);

            Console.WriteLine("ok");
            Console.ReadLine();
        }

        static void TestNewtonSoft(List<Person> list)
        {
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            var st = new Stopwatch();
            st.Start();
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            st.Stop();
            Console.WriteLine($"{"1 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"100 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"1000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"10000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒");
        }

        static void TestSystemTextJson(List<Person> list)
        {
            System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list));
            var st = new Stopwatch();
            st.Start();
            System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list));
            st.Stop();
            Console.WriteLine($"{"1 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list));
            }
            st.Stop();
            Console.WriteLine($"{"100 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list));
            }
            st.Stop();
            Console.WriteLine($"{"1000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list));
            }
            st.Stop();
            Console.WriteLine($"{"10000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒");
        }

        static void TestToJson(List<Person> list)
        {
            list.ToJson().ToObject<List<Person>>();
            var options = JsonHelper.GetDefaultJsonSerializerOptions();
            System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list, options), options);
            var st = new Stopwatch();
            st.Start();
            System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list, options), options);
            st.Stop();
            Console.WriteLine($"{"1 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list, options), options);
            }
            st.Stop();
            Console.WriteLine($"{"100 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list, options), options);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                System.Text.Json.JsonSerializer.Deserialize<List<Person>>(System.Text.Json.JsonSerializer.Serialize(list, options), options);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒");
        }

        static void TestToJsonOptions(List<Person> list)
        {
            var options = JsonHelper.GetDefaultJsonSerializerOptions();
            list.ToJson(options).ToObject<List<Person>>(options);
            var st = new Stopwatch();
            st.Start();
            list.ToJson(options).ToObject<List<Person>>(options);
            st.Stop();
            Console.WriteLine($"{"1 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.ToJson(options).ToObject<List<Person>>(options);
            }
            st.Stop();
            Console.WriteLine($"{"100 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.ToJson(options).ToObject<List<Person>>(options);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.ToJson(options).ToObject<List<Person>>(options);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次".PadLeft(10)}\t\t\t\t耗时: {st.ElapsedMilliseconds.ToString().PadRight(10)} 毫秒，\t\t\t平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒");
        }
    }

    [Serializable]
    class Person
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public int Age { get; set; }
        public DateTime Birth { get; set; }
        public double Score { get; set; }
        public DateTime CreateTime { get; set; }
        public DateTime UpdateTime { get; set; }
        public EnumState State { get; set; }
        public string? Desc { get; set; }
        public string? DescNull { get; set; }
        public string Phone { get; set; }

        public int? IdNull { get; set; }
        public int? IdNull2 { get; set; }
        public DateTime? CreateTimeNull { get; set; }
        public DateTime? CreateTimeNull2 { get; set; }
        public EnumState? StateNull { get; set; }
        public EnumState? StateNull2 { get; set; }
    }

    enum EnumState { Normal, Freeze }
}